

#include <assert.h>
#include <gfx/vertexdeclaration.h>
#include <map>

namespace
{
const VertexElement* find_element (const VertexElement* elems, unsigned stream, unsigned idx)
{
  unsigned v=0;
  for (const VertexElement* ve = elems; ve->binding != ASB_Undefined; ve++)
    {
      if (ve->stream != stream)
        {
          continue;
        }
      if (v == idx)
        {
          return ve;
        }
      v++;
    }
  return 0;
}

void copy_element (VertexElement* dst, const VertexElement* src)
{
  assert (dst);
  if (src)
    {
      dst->binding = src->binding;
      dst->offset = src->offset;
      dst->size = src->size;
      dst->stream = src->stream;
      dst->stride = src->stride;
    }
  else
    {
      dst->binding = ASB_Undefined;
    }

}
}

VertexDeclaration::VertexDeclaration(const VertexElement* elements)
  : _streams(0)
  , _elements (0)
{

  // evaluate the number of streams and the number of elements per stream
  std::map<unsigned, unsigned> str;
  for (const VertexElement* vptr=elements; vptr->binding != ASB_Undefined; vptr++)
    {
      (str[vptr->stream])++;
      _streams = _streams < vptr->stream ? vptr->stream : _streams;
    }
  _streams++;

  // now create elements grouped by the streams.
  _elements = new VertexElement*[_streams];
  for (unsigned i=0; i<_streams; i++)
    {
      unsigned numElems = str[i]+1;
      // create the elements for this stream
      _elements[i] = new VertexElement[numElems];

      for (unsigned j=0; j<numElems; j++)
        {
          copy_element(&_elements[i][j], find_element(elements, i, j));
        }
    }
}

VertexDeclaration::~VertexDeclaration()
{
  for (unsigned i=0; i<_streams; i++)
    {
      delete [] _elements[i];
    }
  delete [] _elements;
}


unsigned VertexDeclaration::GetNumberOfStreams() const
{
  return _streams;
}

const VertexElement* VertexDeclaration::GetElements(unsigned stream) const
{
  assert (stream < _streams);

  return _elements[stream];
}


